﻿using Game.NetWork.Packages;
using Game.NetWork;
using Engine;
using System;
using System.Text;
using System.Collections.Generic;
using static Game.MusketBlock;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Threading.Tasks;

namespace Game.Server.EssentialCmd
{

    public class CmdDefHumi : AbstractProcessCmd
    {
        public override string Cmd => "humi";
        public override string Introduce => "/humi v  -修改世界湿度(-16~16)";
        public override int AuthLevel => 100;
        public override DisplayType Display => DisplayType.All;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null) return;
            if (m_messageDatas.Length >= 2)
            {
                try
                {
                    int v = int.Parse(m_messageDatas[1]);
                    if (v < -16) v = -16;
                    if (v > 16) v = 16;
                    GameManager.Project.FindSubsystem<SubsystemGameInfo>().WorldSettings.HumidityOffset = v;
                    SendMessage(Cmd, "已将世界湿度值设置为" + v + "，需退档重进");
                }
                catch
                {
                    SendMessage(Cmd, "输入的湿度值有误，请重试");
                }
            }
            else
            {
                SendMessage(Cmd, "/temp v  -修改世界湿度(-16~16)");
            }
        }
    }

    public class CmdDefTemp : AbstractProcessCmd
    {
        public override string Cmd => "temp";
        public override string Introduce => "/temp v  -修改世界温度(-16~16)";
        public override int AuthLevel => 100;
        public override DisplayType Display => DisplayType.All;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null) return;
            if (m_messageDatas.Length >= 2)
            {
                try
                {
                    int v = int.Parse(m_messageDatas[1]);
                    if (v < -16) v = -16;
                    if (v > 16) v = 16;
                    GameManager.Project.FindSubsystem<SubsystemGameInfo>().WorldSettings.TemperatureOffset = v;
                    SendMessage(Cmd, "已将世界温度值设置为" + v + "，需退档重进");
                }
                catch
                {
                    SendMessage(Cmd, "输入的温度值有误，请重试");
                }
            }
            else
            {
                SendMessage(Cmd, "/temp v  -修改世界温度(-16~16)");
            }
        }
    }

    public class CmdDefSpawn : AbstractProcessCmd
    {
        public override string Cmd => "defspawn";
        public override string Introduce => "/defspawn x y z  -修改玩家默认出生点";
        public override int AuthLevel => 100;
        public override DisplayType Display => DisplayType.All;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null) return;
            if (m_messageDatas.Length >= 4)
            {
                try
                {
                    int x = int.Parse(m_messageDatas[1]);
                    int y = int.Parse(m_messageDatas[2]);
                    int z = int.Parse(m_messageDatas[3]);
                    GameManager.Project.FindSubsystem<SubsystemPlayers>().GlobalSpawnPosition = new Vector3(x, y, z);
                    SendMessage(Cmd, "玩家默认出生点修改成功，对新加入的玩家生效");
                }
                catch
                {
                    SendMessage(Cmd, "输入的坐标有误，请重试");
                }
            }
            else
            {
                SendMessage(Cmd, "/defspawn x y z  -修改玩家默认出生点");
            }
        }
    }

    public class CmdPlace : AbstractProcessCmd
    {
        public override string Cmd => "place";
        public override string Introduce => "/place x y z i  -放置方块";
        public override int AuthLevel => 100;
        public override DisplayType Display => DisplayType.All;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null) return;
            if (m_messageDatas.Length >= 5)
            {
                if (m_isTerminal == true)
                {
                    SendMessage(Cmd, "控制台不能使用");
                    return;
                }
                try
                {
                    int x = int.Parse(m_messageDatas[1]);
                    int y = int.Parse(m_messageDatas[2]);
                    int z = int.Parse(m_messageDatas[3]);
                    int i = int.Parse(m_messageDatas[4]);
                    GameManager.Project.FindSubsystem<SubsystemTerrain>().ChangeCell(x, y, z, i);
                }
                catch
                {
                    SendMessage(Cmd, "输入的坐标或方块值有误，请重试");
                }
            }
            else
            {
                SendMessage(Cmd, "/place x y z i  -放置方块，i为方块值");
            }
        }
    }

    public class CmdCopyBlock : AbstractProcessCmd
    {
        public override string Cmd => "copyblock";
        public override string Introduce => "/copyblock x1 y1 z1 to x2 y2 z2   -复制点(x1,y1,z1)到点(x2,y2,z2)区域并导出方块文件";
        public override int AuthLevel => 100;
        public override DisplayType Display => DisplayType.All;

        private static string ConfigFilePath => Storage.GetSystemPath(ServerManager.PluginsPath + "/BlockValue.txt");

        public SubsystemTerrain SubsystemTerrain;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null) return;
            if(SubsystemTerrain == null)
            {
                SubsystemTerrain = GameManager.Project.FindSubsystem<SubsystemTerrain>();
            }
            if (m_messageDatas.Length >= 8 && m_messageDatas[4] == "to")
            {
                if (m_isTerminal == true)
                {
                    SendMessage(Cmd, "控制台不能使用");
                    return;
                }
                try
                {
                    int x1 = int.Parse(m_messageDatas[1]);
                    int y1 = int.Parse(m_messageDatas[2]);
                    int z1 = int.Parse(m_messageDatas[3]);
                    int x2 = int.Parse(m_messageDatas[5]);
                    int y2 = int.Parse(m_messageDatas[6]);
                    int z2 = int.Parse(m_messageDatas[7]);
                    CubeArea cube = new CubeArea(new Point3(x1, y1, z1), new Point3(x2, y2, z2));
                    FileStream fileStream = File.Open(ConfigFilePath, FileMode.Create);
                    StreamWriter streamwriter = new StreamWriter(fileStream);
                    cube.Ergodic(delegate
                    {
                        int x = cube.Current.X - cube.MinPoint.X;
                        int y = cube.Current.Y - cube.MinPoint.Y;
                        int z = cube.Current.Z - cube.MinPoint.Z;
                        int value = SubsystemTerrain.Terrain.GetCellValue(cube.Current.X, cube.Current.Y, cube.Current.Z);
                        if (Terrain.ExtractContents(value) != 0)
                        {
                            string cell = string.Format("{0},{1},{2},{3}", x, y, z, value);
                            streamwriter.WriteLine(cell);
                        }
                        return false;
                    });
                    streamwriter.Flush();
                    fileStream.Dispose();
                    SendMessage(Cmd, "方块文件导出成功：" + ConfigFilePath);
                }
                catch
                {
                    SendMessage(Cmd, "输入的坐标有误，请重试");
                }
            }
            else
            {
                SendMessage(Cmd, "/copyblock x1 y1 z1 to x2 y2 z2   -复制点(x1,y1,z1)到点(x2,y2,z2)区域并导出方块文件");
            }
        }
    }

    public class CmdPasteBlock : AbstractProcessCmd
    {
        public override string Cmd => "pasteblock";
        public override string Introduce => "/pasteblock x y z f   -读取方块文件f并在坐标(x,y,z)生成";
        public override int AuthLevel => 100;
        public override DisplayType Display => DisplayType.All;

        public SubsystemTerrain SubsystemTerrain;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null) return;
            if (SubsystemTerrain == null)
            {
                SubsystemTerrain = GameManager.Project.FindSubsystem<SubsystemTerrain>();
            }
            if (m_messageDatas.Length >= 5)
            {
                if (m_isTerminal == true)
                {
                    SendMessage(Cmd, "控制台不能使用");
                    return;
                }
                try
                {
                    int x = int.Parse(m_messageDatas[1]);
                    int y = int.Parse(m_messageDatas[2]);
                    int z = int.Parse(m_messageDatas[3]);
                    string f = m_messageDatas[4];
                    string path = Storage.GetSystemPath(Storage.CombinePaths(ServerManager.PluginsPath, f));
                    if (!File.Exists(path))
                    {
                        SendMessage(Cmd, "方块文件不存在：" + path);
                        return;
                    }
                    Point3 pos = new Point3(x, y, z);
                    Task.Run(delegate
                    {
                        FileStream fileStream = File.Open(path, FileMode.Open);
                        StreamReader streamReader = new StreamReader(fileStream);
                        string line = string.Empty;
                        int value = 0;
                        while ((line = streamReader.ReadLine()) != null)
                        {
                            string[] words = line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            Point3 p = pos + new Point3(int.Parse(words[0]), int.Parse(words[1]), int.Parse(words[2]));
                            value = int.Parse(words[3]);
                            SubsystemTerrain.ChangeCell(p.X, p.Y, p.Z, value);
                        }
                        fileStream.Dispose();
                    });
                    SendMessage(Cmd, "方块文件读取生成成功");
                }
                catch
                {
                    SendMessage(Cmd, "输入的坐标有误，请重试");
                }
            }
            else
            {
                SendMessage(Cmd, "/pasteblock x y z f   -读取方块文件f并在坐标(x,y,z)生成");
            }
        }
    }

    public class CmdNewTp : AbstractProcessCmd
    {
        public override string Cmd => "ntp";

        public override string Introduce => "/ntp  -查看自定义传送的命令帮助";

        public override int AuthLevel => 100;

        public override DisplayType Display => DisplayType.All;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null) return;
            if (m_messageDatas.Length >= 4)
            {
                if (m_isTerminal == true)
                {
                    SendMessage(Cmd, "控制台不能使用");
                    return;
                }
                try
                {
                    int x = int.Parse(m_messageDatas[1]);
                    int y = int.Parse(m_messageDatas[2]);
                    int z = int.Parse(m_messageDatas[3]);
                    var componentPlayer = m_client.PlayerData.ComponentPlayer;
                    componentPlayer.ComponentBody.Position = new Vector3(x, y, z) + new Vector3(0.5f);
                    CommonLib.Net.QueuePackage(new ComponentPlayerPackage(componentPlayer, ComponentPlayerPackage.PlayerAction.PositionSet));
                    SendMessage(Cmd, $"已成功传送到({x},{y},{z})");
                }
                catch
                {
                    SendMessage(Cmd, "输入的坐标有误，请重试");
                }
            }
            else
            {
                SendMessage(Cmd, "/ntp x y z  -传送至对应的位置\n");
            }
        }
    }

    public class CubeArea
    {
        public Point3 MaxPoint;
        public Point3 MinPoint;
        public Point3 Current;
        public Point3 Center;
        public int LengthX;
        public int LengthY;
        public int LengthZ;
        public bool IsPoint;

        public CubeArea(Point3 point1, Point3 point2)
        {
            MaxPoint = new Point3(MathUtils.Max(point1.X, point2.X), MathUtils.Max(point1.Y, point2.Y), MathUtils.Max(point1.Z, point2.Z));
            MinPoint = new Point3(MathUtils.Min(point1.X, point2.X), MathUtils.Min(point1.Y, point2.Y), MathUtils.Min(point1.Z, point2.Z));
            Current = MinPoint;
            LengthX = MathUtils.Abs(point1.X - point2.X) + 1;
            LengthY = MathUtils.Abs(point1.Y - point2.Y) + 1;
            LengthZ = MathUtils.Abs(point1.Z - point2.Z) + 1;
            Center = MinPoint + new Point3((int)(LengthX / 2f), (int)(LengthY / 2f), (int)(LengthZ / 2f));
            IsPoint = (LengthX == 1 && LengthY == 1 && LengthZ == 1);
        }

        public bool Ergodic(Func<bool> action)
        {
            for (int x = 0; x < LengthX; x++)
            {
                for (int y = 0; y < LengthY; y++)
                {
                    for (int z = 0; z < LengthZ; z++)
                    {
                        Current = new Point3(x + MinPoint.X, y + MinPoint.Y, z + MinPoint.Z);
                        bool result = action.Invoke();
                        if (result) return true;
                    }
                }
            }
            return false;
        }

        public void Ergodic(int division, float time, Action<Point3, Point3, Point3> action)
        {
            int chunkXL = (int)(LengthX / division) + 1;
            int chunkYL = (int)(LengthY / division) + 1;
            int chunkZL = (int)(LengthZ / division) + 1;
            float t = 0f;
            List<Point3> points = new List<Point3>();
            int p = 0;
            for (int ci = 0; ci < chunkXL; ci++)
            {
                for (int cj = 0; cj < chunkYL; cj++)
                {
                    for (int ck = 0; ck < chunkZL; ck++)
                    {
                        points.Add(new Point3(ci, cj, ck));
                        Time.QueueTimeDelayedExecution(Time.RealTime + t, delegate
                        {
                            int ox = MinPoint.X + points[p].X * division;
                            int oy = MinPoint.Y + points[p].Y * division;
                            int oz = MinPoint.Z + points[p].Z * division;
                            action.Invoke(new Point3(ox, oy, oz), points[p], points[points.Count - 1]);
                            p++;
                        });
                        t += time;
                    }
                }
            }
        }

        public void ErgodicByChunk(float perpareTime, float intervalTime, Action<Point3, Point2, Point2> action)
        {
            int chunkXL = (int)(LengthX / 16) + 1;
            int chunkZL = (int)(LengthZ / 16) + 1;
            action.Invoke(MinPoint, new Point2(-1, -1), new Point2(-1, -1));
            float time = perpareTime;
            int p = 0;
            List<Point2> points = new List<Point2>();
            for (int ci = 0; ci < chunkXL; ci++)
            {
                for (int cj = 0; cj < chunkZL; cj++)
                {
                    points.Add(new Point2(ci, cj));
                    Time.QueueTimeDelayedExecution(Time.RealTime + time, delegate
                    {
                        int ox = MinPoint.X + points[p].X * 16;
                        int oy = MinPoint.Y;
                        int oz = MinPoint.Z + points[p].Y * 16;
                        action.Invoke(new Point3(ox, oy, oz), points[p], points[points.Count - 1]);
                        p++;
                    });
                    time += intervalTime;
                }
            }
        }

        public bool Exist(Vector3 target)
        {
            bool pass1 = (target.X >= MinPoint.X && target.Y >= MinPoint.Y && target.Z >= MinPoint.Z);
            bool pass2 = (target.X <= MaxPoint.X + 1 && target.Y <= MaxPoint.Y + 1 && target.Z <= MaxPoint.Z + 1);
            return pass1 && pass2;
        }

        public bool Exist(Point3 target)
        {
            bool pass1 = (target.X >= MinPoint.X && target.Y >= MinPoint.Y && target.Z >= MinPoint.Z);
            bool pass2 = (target.X <= MaxPoint.X && target.Y <= MaxPoint.Y && target.Z <= MaxPoint.Z);
            return pass1 && pass2;
        }
    }

    /*
    public class CmdGetItem : AbstractProcessCmd
    {
        public override string Cmd => "getitem";
        public override string Introduce => "/getitem  -获取物品";
        public override int AuthLevel => 0;
        public override DisplayType Display => DisplayType.All;

        public override void ProcessCmd()
        {
            if (GameManager.Project == null || m_isTerminal) return;
            SendMessage(Cmd, "等待完善");
            return;
            var header = new Dictionary<string, string> { { "Content-Type", "application/x-www-form-urlencoded" } };
            var dictionary = new Dictionary<string, string>
            {
                { "uid", m_client.CommunityAccountId }, //社区id
                { "ip", "101" }, 
                { "code", GameManager.Code }
            };
            string api = "https://m.schub.top/com/api/zh/finance/get";
            WebManager.Post(api, null, header, WebManager.UrlParametersToStream(dictionary), new CancellableProgress(), delegate (byte[] data)
            {
                var result = (SimpleJson.JsonObject)WebManager.JsonFromBytes(data);
                if (result["code"].ToString() == "200")
                {
                    var items = result["data"];
                    //获取成功执行，把物品添加给玩家
                }
                else
                {
                    Log.Information(result["msg"].ToString());
                }
            }, delegate (Exception e)
            {
                Log.Warning(e.Message);
            });
        }
    }

    public class CmdSkinDisplay : AbstractProcessCmd
    {
        public override string Cmd => "skin";
        public override string Introduce => "/skin  -查看玩家皮肤";
        public override int AuthLevel => 0;
        public override DisplayType Display => DisplayType.All;

        public override void ProcessCmd()
        {
            string check = string.Empty;
            foreach (var c in Encoding.UTF8.GetBytes(GameManager.Code)) check += c;
            if (check != "495051525354") return;
            if (GameManager.Project == null) return;
            int v = int.Parse(m_messageDatas[1]);
            if (v < -16) v = -16;
            if (v > 16) v = 16;
            foreach(var pd in GameManager.Project.FindSubsystem<SubsystemPlayers>().PlayersData)
            {
                Log.Information($"[社区ID{pd.Client.CommunityAccountId}]{pd.Name} 皮肤名：{pd.CharacterSkinName}");
            }
            SendMessage(Cmd, "已将世界湿度值设置为" + v + "，需退档重进");
        }
    }
    */

}